home *** CD-ROM | disk | FTP | other *** search
/ Language/OS - Multiplatform Resource Library / LANGUAGE OS.iso / a_utils / _archvrs / unix / tcx-1_0.lha / tcx-1.0 / untcx.c < prev    next >
C/C++ Source or Header  |  1993-03-30  |  28KB  |  1,204 lines

  1. /* untcx.c, Version 1.0, 25/3/1993 by Stewart Forster */
  2.  
  3. /************************************************************************/
  4. /*   Copyright (C) 1993 Stewart Forster                    */
  5. /*  This program is free software; you can redistribute it and/or modify*/
  6. /*  it under the terms of the GNU General Public License as published by*/
  7. /*  the Free Software Foundation; either version 2, or (at your option) */
  8. /*  any later version.                            */
  9. /*                                    */
  10. /*  This program is distributed in the hope that it will be useful,    */
  11. /*  but WITHOUT ANY WARRANTY; without even the implied warranty of    */
  12. /*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the    */
  13. /*  GNU General Public License for more details.            */
  14. /*                                    */
  15. /*  You should have received a copy of the GNU General Public License    */
  16. /*  along with this program; if not, write to the Free Software        */
  17. /*  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.        */
  18. /************************************************************************/
  19.  
  20. #include    "config.h"
  21.  
  22. typedef struct path
  23. {
  24.     char    path[MAXPATHLEN]; /* Pathname to file */
  25.     int    pid;        /* Process id compressing file */
  26.     int    local;        /* Is file local? */
  27.     int    ctime;        /* Inode modification time */
  28.     struct    path    *next;    /* Next structure */
  29. } path;
  30.  
  31. #if defined(SUNOS)
  32. #define    MAXOPENFILES    4096
  33. #define    PIHASH(a, b)    (((a) + (b)) % MAXOPENFILES)
  34.  
  35. typedef struct pstat
  36. {
  37.     int    dev;
  38.     int    ino;
  39.     struct    pstat    *next;
  40. } pstat;
  41.  
  42. pstat    parr[MAXOPENFILES];
  43. pstat    *pihash[MAXOPENFILES];
  44. void    update_pstat_info();
  45. #endif
  46.  
  47. extern    int    errno;
  48. path    *worklist = NULL, *freelist = NULL;
  49.  
  50.  
  51. char    logpath[MAXPATHLEN], logtmppath[MAXPATHLEN], lockpath[MAXPATHLEN];
  52.  
  53. void    untcx_and_exec_local(char *, char *, char *[]);
  54. void    untcx_and_exec_nfs(char *, char *, char *, char *[]);
  55. int    try_to_exec(char *, char *[]);
  56. void    check_tcxd_mode();
  57. int    tcxd_reaper();
  58. void    just_untcx(char *, char *);
  59. int    scan_logtail(int);
  60. int    is_dir_local(char *);
  61. int    is_tcx(int);
  62. int    dodecode(int, int);
  63. char    *newargs[1024];
  64. #ifdef ULTRIX
  65. int    usleep(int);
  66. int    usleep_sig();
  67. #endif
  68.  
  69. int
  70. main(int argc, char *argv[])
  71. {
  72. char    cwd[MAXPATHLEN];    /* Save of current working directory */
  73. char    realdir[MAXPATHLEN];    /* Real directory packed executable lives in */
  74. char    execname[MAXPATHLEN];    /* Name of packed/target executable */
  75. char    execpath[MAXPATHLEN];    /* Full path name of packed executable */
  76. char    untcxtmp[MAXPATHLEN];    /* Temporary unpack pathname */
  77. char    tcxtarg[MAXPATHLEN];    /* Target path name of unpacked executable */
  78. char    *c;            /* String manipulation pointers */
  79. struct    stat    dostat;    /* Stat buffer */
  80. int    i, local, isinterp;
  81.  
  82.     if(argc < 2)
  83.     {
  84.         (void)fprintf(stderr, "Usage: %s filename\n", argv[0]);
  85.         exit(-1);
  86.     }
  87.  
  88.     /* Re-exec if not root and pass -x along on the command line. */
  89.     /* If it's there when we restart and we're still not root, then */
  90.     /* avoid an exec loop by quitting with a warning. */
  91.  
  92.     if(geteuid() != 0)
  93.     {
  94.         if(strcmp(argv[1], "-x") == 0)
  95.         {
  96.             (void)fprintf(stderr, "Error: untcx is not installed setuid!\n");
  97.             (void)fprintf(stderr, "Contact your systems administrator\n");
  98.             exit(-1);
  99.         }
  100.  
  101.         /* Push -x into argv[1] and shift rest of args along */
  102.  
  103.         newargs[0] = argv[0];
  104.         newargs[1] = "-x";
  105.         for(i = 1; i < argc; i++) newargs[i+1] = argv[i];
  106.         newargs[i + 1] = (char *)NULL;
  107.         if(execv(PATHUNTCX, newargs) < 0)
  108.             perror("exec");
  109.  
  110.         /* exec failed! Warn user and quit */
  111.  
  112.         (void)fprintf(stderr, "Unable to invoke interpreter as root\n");
  113.         exit(-1);
  114.     }
  115.  
  116.     if(strcmp(argv[1], "-x") == 0)
  117.     {
  118.         for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  119.         argv[i] = (char *)NULL;
  120.         --argc;
  121.         isinterp = 1;
  122.     }
  123.     else
  124.     if(strcmp(argv[1], "-u") == 0)
  125.     {
  126.         for(i = 1; i < (argc - 1); i++) argv[i] = argv[i+1];
  127.         argv[i] = (char *)NULL;
  128.         --argc;
  129.         isinterp = 0;
  130.     }
  131.     else
  132.     if(getuid() == 0)
  133.         isinterp = 1;
  134.     else
  135.         isinterp = 0;
  136.  
  137.     /* Copy argv[1] to argv[0] for obsolete stuff (and IRIX) */
  138.  
  139.     argv[0] = argv[1];
  140.  
  141.     /* Setup to catch all undesirable signals */
  142.  
  143.     (void)signal(SIGINT, SIG_IGN);
  144.     (void)signal(SIGHUP, SIG_IGN);
  145.     (void)signal(SIGTSTP, SIG_IGN);
  146.     (void)signal(SIGALRM, SIG_IGN);
  147.     (void)signal(SIGQUIT, SIG_IGN);
  148.     (void)signal(SIGTERM, SIG_IGN);
  149.  
  150.     /* Set global paths */
  151.  
  152.     (void)sprintf(logpath, "%s/log", ENFSDIR);
  153.     (void)sprintf(logtmppath, "%s/logtmp", ENFSDIR);
  154.     (void)sprintf(lockpath, "%s/.lock", ENFSDIR);
  155.  
  156.     /* Check and start tcxd as required */
  157.  
  158.     check_tcxd_mode();
  159.  
  160.     /* Go to the uid of invoking user.  Resolve through symbolic links */
  161.     /* as to what the real pathname of the executable is. */
  162.  
  163.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  164.  
  165.     /* Grab argv[0] and resolve to full path name via getwd() */
  166.  
  167.     if(getwd(cwd) == NULL)
  168.     {
  169.         (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  170.         exit(-1);
  171.     }
  172.  
  173.     if(*argv[0] == '/')
  174.         (void)strcpy(realdir, argv[0]);
  175.     else
  176.         (void)sprintf(realdir, "%s/%s", cwd, argv[0]);
  177.     for(;;)
  178.     {
  179.         if((c = strrchr(realdir, '/')) == NULL)
  180.         {    /* Should never happen, BUT... */
  181.             (void)fprintf(stderr, "Help! Internal corruption of variables!\n");
  182.             exit(-1);
  183.         }
  184.         c++;
  185.         (void)strcpy(execname, c);
  186.         *c = '\0';
  187.  
  188.         if(chdir(realdir) < 0)    /* Oops. Failed. Report and quit. */
  189.         {
  190.             perror(realdir);
  191.             exit(-1);
  192.         }
  193.  
  194.         if(getwd(cwd) == NULL)
  195.         {
  196.             (void)fprintf(stderr, "Get Working Directory Error: %s\n", cwd);
  197.             exit(-1);
  198.         }
  199.  
  200.         /* Do lstat executable from here. If not a link, go on, else */
  201.         /* read the value of the link, and append it to realdir if */
  202.         /* it doesn't begin with a /, other just copy it to realdir */
  203.         /* and cycle through the loop again. */
  204.  
  205.         if(lstat(execname, &dostat) < 0)
  206.         {
  207.             perror(execname);
  208.             exit(-1);
  209.         }
  210.  
  211.         if((dostat.st_mode & S_IFMT) == S_IFLNK)
  212.         {
  213.             if(readlink(execname, execpath, MAXPATHLEN) < 0)
  214.             {
  215.                 perror(execname);
  216.                 exit(-1);
  217.             }
  218.             if(execpath[0] == '/')
  219.                 (void)strcpy(realdir, execpath);
  220.             else
  221.             {
  222.                 (void)strcat(realdir, "/");
  223.                 (void)strcat(realdir, execpath);
  224.             }
  225.             continue;
  226.         }
  227.  
  228.         if(!(dostat.st_mode & S_IFREG))
  229.         {
  230.             (void)fprintf(stderr, "Error: Not an executable file - %s/%s\n", realdir, execname);
  231.             exit(-1);
  232.         }
  233.  
  234.         /* Now do a statfs on realdir.  If it's on an NFS mounted filesystem we */
  235.         /* will need to unpack to ENFSDIR, otherwise we can unpack it in place, */
  236.         /* fsbuf.f_fstyp tells what filesystem type we're on.  For IRIX this */
  237.         /* appears to be 1 for NFS, and 3 for local based filesystems.  I could */
  238.         /* not find any documentation on this issue, so until a more portable */
  239.         /* method is found, I'll be using these two numbers. */
  240.  
  241.         if((local = is_dir_local(realdir)) < 0)
  242.             exit(-1);
  243.  
  244.         break;
  245.     }
  246.  
  247.     /* Return to the original invocation directory */
  248.  
  249.     if(chdir(cwd) < 0)    /* Oops. Failed again! Try as user again! */
  250.     {
  251.         perror(cwd);
  252.         exit(-1);
  253.     }
  254.  
  255.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  256.  
  257.     /* Now check if last components of argv[0] and argv[1] are equal */
  258.     /* If not, we are invoked just to decompress something, not to */
  259.     /* execute it.  Just attempt an uncompress as the user */
  260.  
  261.     if(isinterp == 0)
  262.     {
  263. #if defined(IRIX)
  264.         if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  265. #else
  266.         if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  267. #endif
  268.         (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  269.         (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  270.         just_untcx(tcxtarg, untcxtmp);
  271.         exit(0);
  272.     }
  273.  
  274.     /* Try to do a local execute. If it returns, it means failure. */
  275.  
  276.     if(local)
  277.     {
  278.         (void)sprintf(tcxtarg, "%s/%s", realdir, execname);
  279.         (void)sprintf(untcxtmp, "%s/.untcx.%s", realdir, execname);
  280.         untcx_and_exec_local(tcxtarg, untcxtmp, &(argv[1]));
  281.     }
  282.  
  283.     /* We get this far if file is not local, or the local execution */
  284.     /* failed for some reason like shortage of disk space. Attempt */
  285.     /* to unpack program to /tmp and go from there. */
  286.  
  287.     for(c = realdir; *c ; c++)
  288.         if(*c == '/')
  289.             *c = '=';
  290.     (void)sprintf(tcxtarg, "%s/%s/", ENFSDIR, realdir);
  291.     if(mkdir(tcxtarg, 0777) < 0)
  292.         if(errno != EEXIST)
  293.         {
  294.             perror(tcxtarg);
  295.             exit(-1);
  296.         }
  297.     (void)chmod(tcxtarg, 0777);
  298.     (void)strcat(tcxtarg, execname);
  299.     (void)sprintf(untcxtmp, "%s/%s/.untcx.%s", ENFSDIR, realdir, execname);
  300.  
  301.     untcx_and_exec_nfs(argv[0], untcxtmp, tcxtarg, &(argv[1]));
  302.  
  303.     /* :-(  We only get this far if everything has failed. Exit with failure */
  304.  
  305.     return(-1);
  306. } /* main */
  307.  
  308.  
  309. void
  310. check_tcxd_mode()
  311. {
  312. char    *s, spid[32];
  313. int    infd, logfd, lkfd, lasttime = 0, timer;
  314. FILE    *logfp;
  315. path    *curr, *prev;
  316. struct    stat    sb;    /* Stat buffer */
  317. struct    flock    lck;    /* File lock structure */
  318. struct    utimbuf    times;
  319. int    lastoff;
  320. #if defined(SUNOS)
  321. pstat    *pc;        /* Hash/search pointer for SUNOS */
  322. int    found;
  323. #endif
  324.  
  325.     /* Check if we're root. If not, go home */
  326.  
  327.     if(geteuid() != 0)
  328.         return;
  329.  
  330.     /* Try to create emergency/NFS execute directory and set it's permissions */
  331.     /* It's not important yet if we can't at this stage. */
  332.  
  333.     (void)mkdir(ENFSDIR, 01777);
  334.     (void)chmod(ENFSDIR, 01777);
  335.  
  336.     /* Attempt to create ENFSDIR/.lock  If can't, just return. */
  337.  
  338.     if((lkfd = open(lockpath, O_CREAT | O_RDONLY, 0600)) < 0)
  339.         return;
  340.  
  341.     /* Attempt to read lock ENFSDIR/.lock If can't, we assume the tcxd */
  342.     /* is already running. Return. */
  343.  
  344.     lck.l_type = F_RDLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  345.     if(fcntl(lkfd, F_SETLK, &lck) < 0)
  346.     {
  347.         (void)close(lkfd);
  348.         return;
  349.     }
  350.  
  351.     /* Close lkfd and hence the lock on it, fork() and return */
  352.  
  353.     (void)close(lkfd);
  354.     if(fork() != 0)    /* On parent or fork error, just return */
  355.         return;
  356.  
  357.     /* No errors to user at this point */
  358.  
  359.     (void)fclose(stderr);
  360.     (void)close(2);
  361.     (void)open("/dev/null", O_WRONLY);    /* Don't really care */
  362.  
  363.     /* Make ourselves nice and rooted */
  364.  
  365. #if defined(IRIX)
  366.     if(setuid(geteuid()) < 0) exit(-1);
  367. #else
  368.     if(setreuid(geteuid(), geteuid()) < 0) exit(-1);
  369. #endif
  370.  
  371.     /* Check if we're root again. If not, exit */
  372.  
  373.     if(geteuid() != 0)
  374.         exit(-1);
  375.  
  376.     /* Change directory to ENFSDIR to prevent hanging on NFS server crashes */
  377.  
  378.     if(chdir(ENFSDIR) < 0)
  379.         exit(-1);
  380.  
  381.     /* Lock the server lock file to prevent more than 1 starting up */
  382.  
  383.     if((lkfd = open(lockpath, O_WRONLY | O_TRUNC)) < 0)
  384.         exit(-1);
  385.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  386.     if(fcntl(lkfd, F_SETLK, &lck) < 0)
  387.         exit(-1);
  388.  
  389.     /* Write our process id to the lock file. Don't really care if fails. */
  390.  
  391.     (void)sprintf(spid, "%d\n", getpid());
  392.     (void)write(lkfd, spid, strlen(spid));
  393.  
  394.     /* setup our child process reaper */
  395.  
  396.     (void)signal(SIGCHLD, tcxd_reaper);
  397.  
  398.     /* Read in log file if it's there in case of crashes */
  399.  
  400.     if((lastoff = scan_logtail(0)) < 0)
  401.         (void)creat(logpath, 0600);
  402.  
  403.     /* Loop doing tasks at hand */
  404.  
  405.     for(;;)
  406.     {
  407.         /* Before starting loop, logfp should be open for reading */
  408.         /* at end of log file. */
  409.  
  410.         lastoff = 0;
  411.         for(timer = 0; timer < SCANRATE; timer++, (void)sleep(1))
  412.         {
  413.             if(stat(logpath, &sb) < 0)
  414.                 continue;
  415.  
  416.             /* Don't check if not updated, but do on last time */
  417.  
  418.             if(sb.st_mtime <= lasttime)
  419.                 continue;
  420.             lasttime = sb.st_mtime;
  421.  
  422.             lastoff = scan_logtail(lastoff);
  423.         }
  424.  
  425. #if defined(SUNOS)
  426.         update_pstat_info();
  427. #endif
  428.  
  429.         for(prev = NULL, curr = worklist; curr != NULL; prev = curr, curr = curr->next)
  430.         {
  431.             /* Stat file. If not accessed within last 30 minutes */
  432.             /* we consider it a candidate for compression */
  433.  
  434.             if(stat(curr->path, &sb) < 0)
  435.             {
  436.                 (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  437.                 curr->next = freelist; freelist = curr;
  438.                 (prev == NULL) ? (curr = worklist) : (curr = prev);
  439.                 if(curr == NULL) break;
  440.                 continue;
  441.             }
  442.  
  443.             if(curr->local==1 && (time(NULL) - sb.st_atime) < LOCALTIMEOUT)
  444.                     continue;
  445.             if(curr->local == 0 && (time(NULL) - sb.st_atime) < ENFSTIMEOUT)
  446.                     continue;
  447.  
  448.             /* Open file for reading and test if readlock exists */
  449.             /* If not, then if file is local, recompress it */
  450.             /* otherwise, unlink it from the ENFSDIR home */
  451.  
  452. #if defined(IRIX) || defined(DEC)
  453.             if((infd = open(curr->path, O_WRONLY)) < 0)
  454.             {
  455.                 if(errno != ETXTBSY)
  456.                 {
  457.                     (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  458.                     curr->next = freelist; freelist = curr;
  459.                     (prev == NULL) ? (curr = worklist) : (curr = prev);
  460.                     if(curr == NULL) break;
  461.                     continue;
  462.                 }
  463.                 times.actime = time(NULL);
  464.                 times.modtime = sb.st_mtime;
  465.                 (void)utime(curr->path, ×);
  466.                 continue;
  467.             }
  468.             (void)close(infd);
  469. #endif
  470.  
  471. #if defined(SUNOS)
  472.             found = 0;
  473.             for(pc = pihash[PIHASH(sb.st_dev, sb.st_ino)]; pc != NULL; pc = pc->next)
  474.                 if(pc->dev == sb.st_dev && pc->ino == sb.st_ino)
  475.                 {
  476.                     times.actime = time(NULL);
  477.                     times.modtime = sb.st_mtime;
  478.                     (void)utime(curr->path, ×);
  479.                     found = 1;
  480.                     break;
  481.                 }
  482.             if(found) continue;
  483. #endif
  484.  
  485.             if(curr->local == -1)    /* Compression completed */
  486.             {
  487.                 (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  488.                 curr->next = freelist; freelist = curr;
  489.                 (prev == NULL) ? (curr = worklist) : (curr = prev);
  490.                 if(curr == NULL) break;
  491.                 continue;
  492.             }
  493.  
  494.             if(curr->pid > 0) continue;
  495.  
  496.             if(curr->local == 1)
  497.             {
  498.                 /* Check inode modification times. If target is */
  499.                 /* newer than what we know, forget it. */
  500.  
  501.                 if(sb.st_ctime > curr->ctime)
  502.                 {
  503.                     (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  504.                     curr->next = freelist; freelist = curr;
  505.                     (prev == NULL) ? (curr = worklist) : (curr = prev);
  506.                     if(curr == NULL) break;
  507.                     continue;
  508.                 }
  509.  
  510.                 /* Fork and compress program */
  511.  
  512.                 curr->pid = fork();
  513.                 if(curr->pid != 0) continue;
  514.  
  515.                 /* Here we must be the child */
  516.                 /* Close stdio stuff and reopen to /dev/null */
  517.  
  518.                 (void)close(2);
  519.                 (void)close(1);
  520.                 (void)close(0);
  521.                 (void)open("/dev/null", O_RDONLY);
  522.                 (void)open("/dev/null", O_WRONLY);
  523.                 (void)open("/dev/null", O_WRONLY);
  524.                 (void)execl(PATHTCX, "tcx", curr->path, (char *)0);
  525.                 exit(-1);
  526.             }
  527.  
  528.             /* At this point, file is in ENFSDIR. Delete it */
  529.  
  530.             (void)unlink(curr->path);
  531.             s = strrchr(curr->path, '/');
  532.             *s = '\0';
  533.             (void)rmdir(curr->path);
  534.  
  535.             (prev == NULL) ? (worklist = curr->next) : (prev->next = curr->next);
  536.             curr->next = freelist; freelist = curr;
  537.             (prev == NULL) ? (curr = worklist) : (curr = prev);
  538.             if(curr == NULL) break;
  539.         } /* for */
  540.  
  541.         /* Update log file in case of crashes */
  542.  
  543.         lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  544.  
  545.         /* Do one final read in case someone has modified during */
  546.         /* the scan sequence. */
  547.  
  548.         (void)scan_logtail(lastoff);
  549.  
  550.         if((logfp = fopen(logtmppath, "w")) == NULL)
  551.             continue;
  552.         for(curr = worklist; curr != NULL; curr = curr->next)
  553.             (void)fprintf(logfp, "%s\n", curr->path);
  554.         (void)fclose(logfp);
  555.  
  556.         /* Try for 20 times to lock file, sleep 5/100ths secs b/w tries */
  557.  
  558.         for(timer = 0; timer < 20; timer++, PUSLEEP(50000))
  559.         {
  560.             if((logfd = open(logpath, O_WRONLY)) < 0)
  561.                 continue;
  562.             if(fcntl(logfd, F_SETLK, &lck) < 0)
  563.             {    (void)close(logfd); continue;    }
  564.  
  565.             (void)rename(logtmppath, logpath);
  566.             (void)close(logfd);
  567.             break;
  568.         }
  569.     } /* for */
  570. } /* check_tcxd_mode */
  571.  
  572.  
  573. int
  574. tcxd_reaper()
  575. {
  576. union    wait    state;
  577. int    pid;
  578. path    *curr;
  579.  
  580.     while((pid = wait3(&state, WNOHANG, 0)) > 0)
  581.         for(curr = worklist; curr != NULL; curr = curr->next)
  582.             if(curr->pid == pid)
  583.             {
  584.                 curr->pid = -1;
  585.                 if(WIFEXITED(state) && WEXITSTATUS(state) == 0)
  586.                     curr->local = -1;
  587.                 break;
  588.             }
  589. } /* tcxd_reaper */
  590.  
  591.  
  592. void
  593. untcx_and_exec_local(char *execpath, char *untcxtmp, char *argv[])
  594. {
  595. struct    stat    tostat;    /* Stat buffer to check on lengths */
  596. int    owner, group;
  597. int    perms;        /* Saved permissions to restore on target exec */
  598. int    infd, outfd;    /* In and out file descriptors */
  599. struct    flock    lck;    /* File lock structure */
  600.  
  601.     /* Stat executable and grab permissions */
  602.  
  603.     if(stat(execpath, &tostat) < 0)
  604.     {
  605.         perror(argv[0]);
  606.         exit(-1);
  607.     }
  608.     perms = (tostat.st_mode & 0777);
  609.     owner = tostat.st_uid;
  610.     group = tostat.st_gid;
  611.  
  612.     for(;;PUSLEEP(10000))
  613.     {
  614.         if((infd = open(execpath, O_RDWR)) < 0)
  615.         {
  616.             if(errno != ETXTBSY)
  617.             {
  618.                 (void)fprintf(stderr, "Cannot write to %s\n", execpath);
  619.                 exit(-1);
  620.             }
  621.             if((infd = open(execpath, O_RDONLY)) < 0)
  622.                 continue;
  623.             (void)close(infd);
  624.             if(try_to_exec(execpath, argv) < 0)
  625.                 exit(-1);
  626.             continue;
  627.         }
  628.  
  629.         lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  630.         if(fcntl(infd, F_SETLK, &lck) < 0)
  631.         {
  632.             if(fcntl(infd, F_GETLK, &lck) < 0 || lck.l_type != F_RDLCK)
  633.             { (void)close(infd); continue; }
  634.             (void)close(infd);
  635.             if(try_to_exec(execpath, argv) < 0)
  636.                 exit(-1);
  637.             continue;
  638.         }
  639.  
  640.         if(! is_tcx(infd))
  641.         {
  642.             (void)close(infd);
  643.             continue;
  644.         }
  645.  
  646.         /* File is in packed format. Unpack it */
  647.  
  648.         if((outfd = open(untcxtmp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  649.         {
  650.             if(errno != EEXIST)
  651.             {
  652.                 perror(untcxtmp);
  653.                 exit(-1);
  654.             }
  655.             if((outfd = open(untcxtmp, O_WRONLY | O_TRUNC)) < 0)
  656.             {
  657.                 perror(untcxtmp);
  658.                 exit(-1);
  659.             }
  660.         }
  661.  
  662.         /* Start decompressing executable */
  663.  
  664.         if(dodecode(infd, outfd) != 0)
  665.         {
  666.             if(unlink(untcxtmp) < 0)
  667.                 perror("untcxtmp");
  668.             exit(-1);
  669.         }
  670.  
  671.         (void)close(outfd);
  672.  
  673.         /* Now set execute permissions on the beastie */
  674.  
  675.         if(chmod(untcxtmp, perms) < 0)
  676.         {
  677.             perror(untcxtmp);
  678.             if(unlink(untcxtmp) < 0)
  679.                 perror("untcxtmp");
  680.             exit(-1);
  681.         }
  682.  
  683.         if(chown(untcxtmp, owner, group) < 0)
  684.         {
  685.             perror(untcxtmp);
  686.             if(unlink(untcxtmp) < 0)
  687.                 perror("untcxtmp");
  688.             exit(-1);
  689.         }
  690.  
  691.         /* Rename temporary file to target executable and close target */
  692.  
  693.         if(rename(untcxtmp, execpath) < 0)
  694.         {
  695.             perror(untcxtmp);
  696.             if(unlink(untcxtmp) < 0)
  697.                 perror("untcxtmp");
  698.             exit(-1);
  699.         }
  700.  
  701.         (void)close(infd);
  702.  
  703.         /* Everything OK!  Now go exec the executable. */
  704.  
  705.         if(try_to_exec(execpath, argv) < 0)
  706.             exit(-1);
  707.     } /* for */
  708. } /* untcx_and_exec_local */
  709.  
  710.  
  711. void
  712. untcx_and_exec_nfs(char *execpath, char *untcxtmp, char *tcxtarg, char *argv[])
  713. {
  714. struct    stat    tostat;    /* Stat buffer to check on lengths */
  715. int    mtime;
  716. int    owner, group;
  717. int    perms;        /* Saved permissions to restore on target exec */
  718. int    infd, outfd;    /* In and out file descriptors */
  719. struct    flock    lck;    /* File lock structure */
  720.  
  721.     /* Stat executable and grab permissions */
  722.  
  723.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  724.     if(stat(execpath, &tostat) < 0)
  725.     {
  726.         perror(argv[0]);
  727.         exit(-1);
  728.     }
  729.     perms = (tostat.st_mode & 0777);
  730.     mtime = tostat.st_mtime;
  731.     owner = tostat.st_uid;
  732.     group = tostat.st_gid;
  733.     if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  734.  
  735.     for(;;PUSLEEP(10000))
  736.     {
  737.         if(stat(tcxtarg, &tostat) >= 0)
  738.             if(mtime > tostat.st_mtime)
  739.                 (void)unlink(tcxtarg);
  740.             else
  741.             {
  742.                 if(try_to_exec(tcxtarg, argv) < 0)
  743.                     exit(-1);
  744.                 continue;
  745.             }
  746.  
  747.         if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  748.         if((infd = open(execpath, O_RDONLY)) < 0)
  749.         {
  750.             perror(execpath);
  751.             exit(-1);
  752.         }
  753.         if(setreuid(geteuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  754.  
  755.         if(! is_tcx(infd))
  756.         {
  757.             (void)close(infd);
  758.             if(try_to_exec(tcxtarg, argv) < 0)
  759.                 exit(-1);
  760.             continue;
  761.         }
  762.  
  763.         /* File is in packed format. Unpack it */
  764.  
  765.         if((outfd = open(untcxtmp, O_EXCL | O_CREAT | O_WRONLY)) < 0)
  766.         {
  767.             if(errno != EEXIST)
  768.             {
  769.                 perror(untcxtmp);
  770.                 exit(-1);
  771.             }
  772.             if((outfd = open(untcxtmp, O_WRONLY | O_TRUNC)) < 0)
  773.             {
  774.                 perror(untcxtmp);
  775.                 exit(-1);
  776.             }
  777.         }
  778.  
  779.         lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  780.         if(fcntl(outfd, F_SETLK, &lck) < 0)
  781.         {
  782.             (void)close(infd);
  783.             (void)close(outfd);
  784.             continue;
  785.         }
  786.  
  787.         /* Start decompressing executable */
  788.  
  789.         if(dodecode(infd, outfd) != 0)
  790.         {
  791.             if(unlink(untcxtmp) < 0)
  792.                 perror(untcxtmp);
  793.             exit(-1);
  794.         }
  795.  
  796.         (void)close(infd);
  797.  
  798.         /* Now set execute permissions on the beastie */
  799.  
  800.         if(chmod(untcxtmp, perms) < 0)
  801.         {
  802.             perror(untcxtmp);
  803.             if(unlink(untcxtmp) < 0)
  804.                 perror(untcxtmp);
  805.             exit(-1);
  806.         }
  807.  
  808.         if(chown(untcxtmp, owner, group) < 0)
  809.         {
  810.             perror(untcxtmp);
  811.             if(unlink(untcxtmp) < 0)
  812.                 perror(untcxtmp);
  813.             exit(-1);
  814.         }
  815.  
  816.         /* Rename temporary file to target executable and close target */
  817.  
  818.         if(rename(untcxtmp, tcxtarg) < 0)
  819.         {
  820.             perror(untcxtmp);
  821.             if(unlink(untcxtmp) < 0)
  822.                 perror(untcxtmp);
  823.             exit(-1);
  824.         }
  825.  
  826.         (void)close(outfd);
  827.  
  828.         /* Everything OK!  Now go exec the executable. */
  829.  
  830.         if(try_to_exec(tcxtarg, argv) < 0)
  831.             exit(-1);
  832.     } /* for */
  833. } /* untcx_and_exec_nfs */
  834.  
  835.  
  836. void
  837. just_untcx(char *execpath, char *untcxtmp)
  838. {
  839. struct    stat    tostat;    /* Stat buffer to check on lengths */
  840. int    owner, group;
  841. int    perms;        /* Saved permissions to restore on target exec */
  842. int    infd, outfd;    /* In and out file descriptors */
  843. struct    flock    lck;    /* File lock structure */
  844.  
  845.     /* Stat executable and grab permissions */
  846.  
  847.     if(stat(execpath, &tostat) < 0)
  848.     {
  849.         perror(execpath);
  850.         exit(-1);
  851.     }
  852.     perms = (tostat.st_mode & 0777);
  853.     owner = tostat.st_uid;
  854.     group = tostat.st_gid;
  855.  
  856.     if((infd = open(execpath, O_RDWR)) < 0)
  857.     {
  858.         perror(execpath);
  859.         exit(-1);
  860.     }
  861.  
  862.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  863.     if(fcntl(infd, F_SETLK, &lck) < 0)
  864.     {
  865.         perror(execpath);
  866.         exit(-1);
  867.     }
  868.  
  869.     if(! is_tcx(infd))
  870.     {
  871.         (void)fprintf(stderr, "File does not appear to be in tcx format. Aborting\n");
  872.         exit(-1);
  873.     }
  874.  
  875.     /* File is in packed format. Unpack it */
  876.  
  877.     if((outfd = open(untcxtmp, O_WRONLY | O_CREAT | O_EXCL)) < 0)
  878.     {
  879.         if(errno != EEXIST)
  880.         {
  881.             perror(untcxtmp);
  882.             exit(-1);
  883.         }
  884.         if((outfd = open(untcxtmp, O_WRONLY | O_TRUNC)) < 0)
  885.         {
  886.             perror(untcxtmp);
  887.             exit(-1);
  888.         }
  889.     }
  890.  
  891.     /* Start decompressing executable */
  892.  
  893.     if(dodecode(infd, outfd) != 0)
  894.     {
  895.         if(unlink(untcxtmp) < 0)
  896.             perror(untcxtmp);
  897.         exit(-1);
  898.     }
  899.  
  900.     (void)close(outfd);
  901.  
  902.     /* Now set execute permissions on the beastie */
  903.  
  904.     if(chmod(untcxtmp, perms) < 0)
  905.     {
  906.         perror(untcxtmp);
  907.         if(unlink(untcxtmp) < 0)
  908.             perror(untcxtmp);
  909.         exit(-1);
  910.     }
  911.  
  912.     if(chown(untcxtmp, owner, group) < 0)
  913.     {
  914.         perror(untcxtmp);
  915.         if(unlink(untcxtmp) < 0)
  916.             perror(untcxtmp);
  917.         exit(-1);
  918.     }
  919.  
  920.     /* Rename temporary file to target executable and close target */
  921.  
  922.     if(rename(untcxtmp, execpath) < 0)
  923.     {
  924.         perror(untcxtmp);
  925.         if(unlink(untcxtmp) < 0)
  926.             perror(untcxtmp);
  927.         exit(-1);
  928.     }
  929.  
  930.     (void)close(infd);
  931.     return;
  932. } /* untcx_and_exec_local */
  933.  
  934.  
  935. int
  936. try_to_exec(char *execpath, char *argv[])
  937. {
  938. int    infd, try;
  939. int    logfd;
  940. FILE    *logfp;
  941. struct    flock    lck;
  942.  
  943.     if((infd = open(execpath, O_RDONLY)) < 0)
  944.     {
  945.         if(errno == ENOENT)
  946.         {
  947.             perror(execpath);
  948.             return -1;
  949.         }
  950.         return 0;
  951.     }
  952.  
  953.     if(is_tcx(infd))
  954.     {
  955.         (void)close(infd);
  956.         return 0;
  957.     }
  958.  
  959.     lck.l_type = F_WRLCK; lck.l_whence = 0; lck.l_start = 0; lck.l_len = 0;
  960.     for(try = 0; try < 10; try++, PUSLEEP(50000))
  961.     {
  962.         if((logfd = open(logpath, O_WRONLY)) < 0)
  963.             continue;
  964.         if(fcntl(logfd, F_SETLK, &lck) < 0)
  965.         {
  966.             (void)close(logfd);
  967.             continue;
  968.         }
  969.  
  970.         if((logfp = fopen(logpath, "a+")) == NULL)
  971.         {
  972.             (void)close(logfd);
  973.             continue;
  974.         }
  975.  
  976.         (void)fprintf(logfp, "%s\n", execpath);
  977.         (void)fclose(logfp);
  978.         (void)close(logfd);
  979.         break;
  980.     }
  981.  
  982. #if defined(IRIX)
  983.     if(setuid(getuid()) < 0) { perror("setuid"); exit(-1); }
  984. #else
  985.     if(setreuid(getuid(), getuid()) < 0) { perror("setreuid"); exit(-1); }
  986. #endif
  987.  
  988.     /* Reset signals back to normal to prevent carriage through execv */
  989.  
  990.     (void)signal(SIGINT, SIG_DFL);
  991.     (void)signal(SIGHUP, SIG_DFL);
  992.     (void)signal(SIGTSTP, SIG_DFL);
  993.     (void)signal(SIGALRM, SIG_DFL);
  994.     (void)signal(SIGQUIT, SIG_DFL);
  995.     (void)signal(SIGTERM, SIG_DFL);
  996.  
  997.     (void)close(infd);
  998.     if(execv(execpath, argv) < 0)
  999.         perror(execpath);
  1000.     return -1;
  1001. } /* try_to_exec */
  1002.  
  1003.  
  1004. #if defined(SUNOS)
  1005. void
  1006. update_pstat_info()
  1007. {
  1008. FILE    *fp;
  1009. char    line[256], tmp[10];
  1010. pstat    *curr;
  1011. int    i, pos;
  1012. int    maj, min, dev, ino, cnt;
  1013.  
  1014.     for(pos = 0 ; pos < MAXOPENFILES; pos++)
  1015.         pihash[pos] = (pstat *)NULL;
  1016.  
  1017.     if((fp = popen(PSTATI, "r")) == NULL)
  1018.         return;
  1019.     if(fgets(line, 256, fp) == NULL)
  1020.         return;
  1021.     for(i = 0; fgets(line, 256, fp) != NULL && i < MAXOPENFILES; i++)
  1022.     {
  1023.         curr = parr + i;
  1024.         strncpy(tmp, line+16, 3);    tmp[3] = '\0';    maj = atoi(tmp);
  1025.         strncpy(tmp, line+20, 3);    tmp[3] = '\0';    min = atoi(tmp);
  1026.         strncpy(tmp, line+23, 6);    tmp[6] = '\0';    ino = atoi(tmp);
  1027.         dev = maj * 256 + min;
  1028.         pos = PIHASH(dev, ino);
  1029.         curr->dev = dev;
  1030.         curr->ino = ino;
  1031.         curr->next = pihash[pos];
  1032.         pihash[pos] = curr;
  1033.     } /* while */
  1034.     parr[i].dev = parr[i].ino = -1;
  1035.     pclose(fp);
  1036. } /* update_pstat_info */
  1037. #endif
  1038.  
  1039.  
  1040. int
  1041. scan_logtail(int lastoff)
  1042. {
  1043. char    newpath[MAXPATHLEN], *s;
  1044. FILE    *logfp;
  1045. path    *curr;
  1046. struct    stat    sb;
  1047.  
  1048.     if(lastoff < 0)
  1049.         lastoff = 0;
  1050.     if((logfp = fopen(logpath, "r")) == NULL)
  1051.         return -1;
  1052.     (void)fseek(logfp, lastoff, SEEK_SET);
  1053.     while(fgets(newpath, MAXPATHLEN, logfp) != NULL)
  1054.     {
  1055.         for(s = newpath; *s; s++) if(*s == '\n') *s = '\0';
  1056.  
  1057.         for(curr = worklist; curr != NULL; curr = curr->next)
  1058.             if(strcmp(curr->path, newpath) == 0) break;
  1059.         if(curr != NULL)
  1060.             continue;
  1061.  
  1062.         if(stat(newpath, &sb) < 0)
  1063.             continue;
  1064.  
  1065.         if(freelist != NULL)
  1066.         {
  1067.             curr = freelist;
  1068.             freelist = freelist->next;
  1069.         }
  1070.         else
  1071.             if((curr = (path *)malloc(sizeof(path))) == NULL)
  1072.                 continue;
  1073.  
  1074.         (void)strcpy(curr->path, newpath);
  1075.         curr->pid = -1;
  1076.         (strstr(newpath, ENFSDIR) == newpath) ? (curr->local = 0) : (curr->local = 1);
  1077.         curr->ctime = sb.st_ctime;
  1078.         curr->next = worklist;
  1079.         worklist = curr;
  1080.     } /* while */
  1081.     lastoff = ftell(logfp);
  1082.     (void)fclose(logfp);
  1083.     return lastoff;
  1084. } /* scan_logtail */
  1085.  
  1086.  
  1087. #ifdef ULTRIX
  1088. int
  1089. is_dir_local(char *dir)
  1090. {
  1091. struct  fs_data fsbuf;
  1092.  
  1093.     if(statfs(dir, &fsbuf) < 1)     /* Returns 0 on "NOT MOUNTED" */
  1094.         return -1;
  1095.  
  1096.     /* NFS Version 2 returns -1 or 0 for both gfree, and gtot */
  1097.     /* to a client, so return false on this condition. */
  1098.  
  1099.     if((fsbuf.fd_req.gfree <= 0) && (fsbuf.fd_req.gtot <= 0))
  1100.         return 0;
  1101.     return 1;
  1102. } /* is_dir_local */
  1103. #else
  1104. int
  1105. is_dir_local(char *dir)
  1106. {
  1107. struct    statfs    fsbuf;    /* Statfs buffer to check local versus NFS executable */
  1108.  
  1109.     if(statfs(dir, &fsbuf, (int)(sizeof(struct statfs)), 0) < 0)
  1110.         return -1;
  1111.  
  1112.     /* NFS Version 2 returns -1 or 0 for both f_files, and f_ffree */
  1113.     /* to a client, so return false on this condition. */
  1114.  
  1115.     if((fsbuf.f_files <= 0) && (fsbuf.f_ffree <= 0))
  1116.         return 0;
  1117.     return 1;
  1118. } /* is_dir_local */
  1119. #endif
  1120.  
  1121.  
  1122. int
  1123. is_tcx(int fd)
  1124. {
  1125. int    i;
  1126. unsigned char    c;
  1127.  
  1128.     for(i = 0; i < 256; i++)
  1129.         if(read(fd, &c, 1) < 1 || c == 0)
  1130.             break;
  1131.     if((i >= 256) || read(fd, &c, 1) < 1  || c != 76 || read(fd, &c, 1) < 1  || c != 193
  1132.         || read(fd, &c, 1) < 1  || c != 13 || read(fd, &c, 1) < 1  || c != 138 )
  1133.         return 0;
  1134.     return 1;
  1135. } /* is_tcx */
  1136.  
  1137.  
  1138. int
  1139. dodecode(int infd, int outfd)
  1140. {
  1141. int    pid;
  1142. union    wait    status;
  1143.  
  1144.     pid = fork();
  1145.     if(pid < 0) return -1;
  1146.     if(pid == 0)
  1147.     {
  1148.         if(dup2(infd, 0) < 0) exit(-1);     /* Attach infd to stdin */
  1149.         (void)close(infd);
  1150.         if(dup2(outfd, 1) < 0) exit(-1); /* Attach outfd to stdout */
  1151.         (void)close(outfd);
  1152. #ifdef    UNPACKOPTS
  1153.         (void)execl(PATHUNPACK, "unpacker", UNPACKOPTS, (char *)0);
  1154. #else
  1155.         (void)execl(PATHUNPACK, "unpacker", (char *)0);
  1156. #endif
  1157.         exit(-1);
  1158.     }
  1159.     else
  1160.         pid = wait(&status);
  1161.     return WEXITSTATUS(status);
  1162. } /* dodecode */
  1163.  
  1164.  
  1165. #ifdef ULTRIX
  1166. int
  1167. usleep(int usec)
  1168. {
  1169. struct    itimerval    value, dumb;
  1170.  
  1171.     (void)signal(SIGALRM, usleep_sig);
  1172.  
  1173.     if(getitimer(ITIMER_REAL, &value) != 0)
  1174.     {
  1175.         perror("Error: couldn't get timer");
  1176.         return(-1);
  1177.     }
  1178.     value.it_value.tv_sec = value.it_interval.tv_sec = (long) usec / 1000000;
  1179.     value.it_value.tv_usec = value.it_interval.tv_usec = (long) usec % 1000000;
  1180.  
  1181.     if(setitimer(ITIMER_REAL, &value, &dumb) != 0) /* ignore parameter 3 */
  1182.     {
  1183.         perror("Error: couldn't set timer");
  1184.         return(-1);
  1185.     }
  1186.  
  1187.     (void)sigpause(SIGALRM);
  1188.  
  1189.     if(getitimer(ITIMER_REAL, &value) != 0)
  1190.     {
  1191.         perror("Error: couldn't get timer");
  1192.         return(-1);
  1193.     }
  1194.     usec = (value.it_value.tv_sec - value.it_interval.tv_sec) * 1000000;
  1195.     usec += (value.it_value.tv_usec - value.it_interval.tv_usec);
  1196.     return usec;
  1197. }
  1198.  
  1199. int
  1200. usleep_sig()
  1201. {
  1202. } /* usleep_sig */
  1203. #endif
  1204.